home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / dec92.zip / 1012024A < prev    next >
Text File  |  1992-10-13  |  10KB  |  312 lines

  1. /*
  2.  * TERM286.C  Copyright (C) 1992 Mark R. Nelson.
  3.  *
  4.  * This file, along with TERM286.H and REAL_ISR.C, make up a simple
  5.  * terminal emulator that will run under the Phar Lap 286|DOS Extender.
  6.  * This program demonstrates the use of a bimodal interrupt handler.
  7.  * The protected mode interrupt is in this routine, the real mode
  8.  * interrupt is found in REAL_ISR.C.  The real mode interrupt is
  9.  * linked into a DLL which is loaded at run time.
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <conio.h>
  17. #include <dos.h>
  18. #include "phapi.h"
  19. #include "term286.h"
  20.  
  21. /*
  22.  * The inline version of outp() for Turbo C will generate a warning
  23.  * message under some circumstances.  This turns off that message
  24.  * by removing the macro the defines the inline version.
  25.  */
  26. #ifdef __TURBOC__
  27. #undef outp
  28. #endif
  29.  
  30. /*
  31.  * These constants define the registers and bits used in setting
  32.  * up the 8250 UART.
  33.  */
  34. #define DIVISOR_LATCH_LSB                  0
  35. #define DIVISOR_LATCH_MSB                  1
  36. #define INTERRUPT_ENABLE_REGISTER          1
  37. #define   IER_RECEIVE_DATA_INTERRUPT       0x01
  38. #define LINE_CONTROL_REGISTER              3
  39. #define   LCR_NUMBER_OF_STOP_BITS          0x04
  40. #define   LCR_PARITY_N                     0x00
  41. #define   LCR_PARITY_O                     0x08
  42. #define   LCR_PARITY_E                     0x18
  43. #define   LCR_DIVISOR_LATCH_ACCESS         0x80
  44. #define MODEM_CONTROL_REGISTER             4
  45. #define   MCR_DATA_TERMINAL_READY          1
  46. #define   MCR_REQUEST_TO_SEND              2
  47. #define   MCR_OUT2                         8
  48. #define LINE_STATUS_REGISTER               5
  49. #define   LSR_THRE                         0x20
  50.  
  51. /*
  52.  * The real mode ISR and the Port data structure are both found in the
  53.  * real mode DLL.  Because of this, they both have to be declared as
  54.  * being far data.
  55.  */
  56. extern struct port_data far Port;
  57. void far interrupt real_isr( void );
  58.  
  59. /*
  60.  * This is the protected mode ISR.  It is identical to the real mode
  61.  * ISR, except for the increment of the protected mode interrupt count
  62.  * near the end.  This routine reads in the character that caused the
  63.  * interrupt, then tries to stuff it in the buffer and update the
  64.  * head pointer.  Finally, it increments the diagnostic counter,
  65.  * outputs an EOI to the 8259 PIC, and exits.
  66.  */
  67.  
  68. void far interrupt prot_isr()
  69. {
  70.     unsigned char c;
  71.     int space_used;
  72.  
  73.     c = ( unsigned char ) inp( Port.uart_address );
  74.     space_used = Port.head_pointer - Port.tail_pointer;
  75.     if ( space_used < 0 )
  76.         space_used += 1024;
  77.     if ( space_used < 1023 ) {
  78.         Port.buffer[ Port.head_pointer++ ] = c;
  79.         Port.head_pointer &= 1023;
  80.     }
  81.     Port.prot_count++;
  82.     outp( 0x20, 0x20 );
  83. }
  84.  
  85. /*
  86.  * This routine sets up the 4 data format parameters for and 8250
  87.  * family UART.  It also does a small amount of error checking, but
  88.  * doesn't affect interrupts.  It can be used before or after the
  89.  * port has been opened.
  90.  */
  91. int SetComParameters( int baud_rate,
  92.                       char parity,
  93.                       int word_length,
  94.                       int stop_bits )
  95. {
  96.     int divisor;
  97.     int lcr_out;
  98.  
  99.     if ( word_length < 5 || word_length > 8 )
  100.         return( 0 );
  101.     lcr_out = word_length - 5;
  102.     switch ( toupper( parity ) ) {
  103.         case 'N' :
  104.             break;
  105.         case 'O' :
  106.             lcr_out |= LCR_PARITY_O;
  107.             break;
  108.         case 'E' :
  109.             lcr_out |= LCR_PARITY_E;
  110.             break;
  111.         default  :
  112.             return( 0 );
  113.     }
  114.     switch ( stop_bits ) {
  115.         case 1  :
  116.             break;
  117.         case 2  :
  118.             lcr_out |= LCR_NUMBER_OF_STOP_BITS;
  119.             break;
  120.         default :
  121.             return( 0 );
  122.     }
  123.     if ( baud_rate < 10 )
  124.         return( 0 );
  125.     divisor = ( int ) ( 115200L / baud_rate ) ;
  126.     outp( Port.uart_address + LINE_CONTROL_REGISTER,
  127.                  LCR_DIVISOR_LATCH_ACCESS );
  128.     outp( Port.uart_address + DIVISOR_LATCH_LSB, divisor & 0xff );
  129.     outp( Port.uart_address + DIVISOR_LATCH_MSB, divisor >> 8 );
  130.     outp( Port.uart_address + LINE_CONTROL_REGISTER, lcr_out );
  131.     return( 1 );
  132. }
  133.  
  134. /*
  135.  * This routine is the one that actually sets up the interrupt
  136.  * routines.  It does this via several calls to Phar Lap 286
  137.  * Extender routines.
  138.  */
  139.  
  140. void SetInterruptVectors( void )
  141. {
  142.     REALPTR real_isr_ptr;
  143.  
  144.     Port.irq_mask = 1 << ( Port.interrupt_number % 8 );
  145.     outp( Port.uart_address + INTERRUPT_ENABLE_REGISTER, 0 );
  146.     real_isr_ptr = DosProtToReal( (PVOID) real_isr );
  147.     if ( real_isr_ptr == 0 )
  148.         exit( 1 );
  149.     DosLockSegPages( SELECTOROF( real_isr ) );
  150.     DosLockSegPages( SELECTOROF( &Port ) );
  151.     DosSetRealProtVec( Port.interrupt_number,
  152.                        (PIHANDLER) prot_isr,
  153.                        real_isr_ptr,
  154.                        (PIHANDLER far *) &Port.old_prot_vector,
  155.                        (REALPTR far *) &Port.old_real_vector );
  156. }
  157.  
  158. /*
  159.  * This routine does everything necessary to open the port so the
  160.  * main program can begin sending and receving characters.  It sets
  161.  * up the UART with the correct data format, then sets up the
  162.  * interrupt service routines, and finally enables interrupts.
  163.  * At that point the UART can now being really doing something.
  164.  */
  165.  
  166. enum port_names { COM1, COM2 };
  167.  
  168. int OpenComPort( enum port_names port_name,
  169.                  unsigned int baud_rate,
  170.                  char parity,
  171.                  unsigned int word_length,
  172.                  unsigned int stop_bits )
  173. {
  174.     int temp;
  175.  
  176.     switch ( port_name ) {
  177.         case COM1 :
  178.             Port.uart_address = 0x3f8;
  179.             Port.interrupt_number = 12;
  180.             break;
  181.         case COM2 :
  182.             Port.uart_address = 0x2f8;
  183.             Port.interrupt_number = 1;;
  184.             break;
  185.         default :
  186.             return 0;
  187.     }
  188.     Port.head_pointer = 0;
  189.     Port.tail_pointer = 0;
  190.     if ( ! SetComParameters( baud_rate, parity, word_length, stop_bits ) )
  191.         return( 0 );
  192.     SetInterruptVectors();
  193. /*
  194.  * This section of code actually enables interrupts.
  195.  */
  196.     temp = inp( 0x21 );
  197.     outp( 0x21, temp & ~Port.irq_mask );
  198.     outp( Port.uart_address + MODEM_CONTROL_REGISTER,
  199.              MCR_DATA_TERMINAL_READY + MCR_REQUEST_TO_SEND + MCR_OUT2 );
  200.     outp( Port.uart_address + INTERRUPT_ENABLE_REGISTER,
  201.               IER_RECEIVE_DATA_INTERRUPT );
  202.     return 1;
  203. }
  204.  
  205. /*
  206.  * This short routine is used to send a character.  All it does is wait
  207.  * for the UART to be ready to accept the character, then stuff it
  208.  * out the UART's transmit register.
  209.  */
  210.  
  211. void SendChar( int c )
  212. {
  213.     int lsr;
  214.  
  215.     for ( ; ; ) {
  216.         lsr = inp( Port.uart_address + LINE_STATUS_REGISTER );
  217.         if ( lsr & LSR_THRE ) {
  218.             outp( Port.uart_address, c );
  219.             return;
  220.         }
  221.     }
  222. }
  223.  
  224. /*
  225.  * This boolean routine lets the main program know whether or not
  226.  * characters are ready to be pulled out of the input buffer.
  227.  */
  228.  
  229. int DataReady( void )
  230. {
  231.     return( Port.head_pointer != Port.tail_pointer );
  232. }
  233.  
  234. /*
  235.  * ReceiveChar reads in a single character from the input buffer, then
  236.  * updates the tail pointer and returns the character.
  237.  */
  238.  
  239. int ReceiveChar( void )
  240. {
  241.     int c;
  242.  
  243.     if ( Port.head_pointer == Port.tail_pointer )
  244.         return( -1 );
  245.     c = Port.buffer[ Port.tail_pointer++ ] & 0xff;
  246.     Port.tail_pointer &= 1023;
  247.     return( c );
  248. }
  249.  
  250. /*
  251.  * CloseComPort() disables interrupts, then restores the old interrupt
  252.  * vectors and unlocks memory.  It also drops DTR and CTS.
  253.  */
  254. void CloseComPort( void )
  255. {
  256.     int temp;
  257.  
  258.     outp( Port.uart_address + INTERRUPT_ENABLE_REGISTER, 0 );
  259.     temp = inp( 0x21 );
  260.     outp( 0x21, temp | Port.irq_mask );
  261.     DosSetRealProtVec( Port.interrupt_number,
  262.                        (PIHANDLER) Port.old_port_vector,
  263.                        (REALPTR) Port.old_real_vector, 0, 0 );
  264.     DosUnlockSegPages( SELECTOROF( real_isr ) );
  265.     DosUnlockSegPages( SELECTOROF( &Port ) );
  266.     outp( Port.uart_address + MODEM_CONTROL_REGISTER, 0 );
  267. }
  268.  
  269. /*
  270.  * The main program opens the port, then sits in a simple loop.  The
  271.  * loop just sends keystrokes out the com ports, and copies input
  272.  * data to the screen.  The only thing unusual is the provision for
  273.  * printing out the port data if the input character is a ^Z.
  274.  */
  275.  
  276. main()
  277. {
  278.     int c;
  279.  
  280.     if ( !OpenComPort( COM1, 2400, 'N', 8, 1 ) ) {
  281.         printf( "Error opening port!\n" );
  282.         return 1;
  283.     }
  284.     for ( ; ; ) {
  285.         if ( kbhit() ) {
  286.             c = getch();
  287.             if ( c == 27 )
  288.                break;
  289.             else if ( c == 26 ) {
  290.                 printf( "\nPort status:\n" );
  291.                 printf( "UART address     : %04.4x\n", Port.uart_address );
  292.                 printf( "Head pointer     : %04.4x\n", Port.head_pointer );
  293.                 printf( "Tail pointer     : %04.4x\n", Port.tail_pointer );
  294.                 printf( "Old prot vector  : %08.8Fp\n", Port.old_prot_vector );
  295.                 printf( "Old real vector  : %08.8Fp\n", Port.old_real_vector );
  296.                 printf( "IRQ mask         : %02.2x\n", Port.irq_mask );
  297.                 printf( "Interrupt number : %02.2x\n", Port.interrupt_number );
  298.                 printf( "Real int count   : %04.4x\n", Port.real_count );
  299.                 printf( "Prot int count   : %04.4x\n", Port.prot_count );
  300.             } else
  301.                 SendChar( c );
  302.         }
  303.         if ( DataReady() ) {
  304.             c = ReceiveChar();
  305.             putch( c );
  306.         }
  307.     }
  308.     CloseComPort();
  309.     return 0;
  310. }
  311.  
  312.